package ie.tippinst.ek;

import java.io.*;
import java.text.DecimalFormat;

/**
 * A utility class that provides an easy interface to standard input and output
 *
 * Adapted from original source from the book "Core Java" by Cay Horstmann
 *
 * Changes are primarily to do with the provision of a robust set of
 * <code>print()</code> and <code>println()</code> methods for output.
 * These have been overloaded to cater for the output of any data type.
 *
 * Other changes include some extra input handling methods to cope with data
 * types not covered in the original
 *
 * @version 3.0
 * @author Cay Horstmann
 * @author Eugene Kenny
 */

public class Console{

    /**
     * Used to
     */

    //private int lineSize;

    // to add printLineRight(type, int width), printRight
    //        printLineCenter, printCenter

    //Change printLine, print methods to call printLine( String), print( String) via toString()
    // cf AlignRight.java

    // ---------------- Start of print() methods ------------

    /**
     * Print a line of text on the console
     * but don't terminate with a newline
     *
     * @param s the String to display
     */

    public static void print( String s){
        System.out.print( s);
        System.out.flush();
    }

    /**
     * Print an object on the console
     * but don't terminate with a newline
     *
     * @param o the Object to display
     */

    public static void print( Object o){
        print( o.toString());
    }

    /**
     * Print a character on the console
     * but don't terminate with a newline
     *
     * @param c the character to display
     */

    public static void print( char c){
        print(Character.toString( c));
    }

    // No need for overridden byte or short methods - will be handled by print( int) method below

    /**
     * Print an integer value on the console
     * but don't terminate with a newline
     *
     * @param i the int value to display
     */

    public static void print( int i){
        print( Integer.toString( i));
    }

    /**
     * Print a long value on the console
     * but don't terminate with a newline
     *
     * @param l the long value to display
     */

    public static void print( long l){
        print( Long.toString( l));
    }

    // No need for overridden float method - will be handled by print( double) method below

    /**
     * Print a floating-point value on the console but don't terminate
     * with a newline
     *
     * @param d the floating-point value to display
     */

    public static void print( double d){
        print( Double.toString( d));
    }

    /**
     * Print a floating-point value to the console but don't terminate
     * with a newline
     * The floating-point value is formatted according to the pattern provided
     *
     * @param d the floating-point value to display
     * @param str the pattern to apply
     */

    public static void print( double d, String str){
        DecimalFormat df = new DecimalFormat( str);
        print( df.format( d));
    }

    /**
     * Print a boolean value on the console
     * but don't terminate with a newline
     *
     * @param b the boolean value to display
     */

    public static void print( boolean b){
        print( Boolean.toString( b));
    }

    // ---------------- End of print() methods ------------
    // ---------------- Start of println() methods ------------

    /**
     * Print a blank line to the console and
     * terminate with a newline
     */

    public static void println(){
        println( "");
    }

    /**
     * Print a line of text to the console and
     * terminate with a newline
     *
     * @param s the String to display
     */

    public static void println( String s){
        System.out.println( s);
        System.out.flush();
    }

    /**
     * Print an object to the console and
     * terminate with a newline
     *
     * @param o the Object to display
     */

    public static void println( Object o){
        println( o.toString());
    }

    /**
     * Print a character to the console and
     * terminate with a newline
     *
     * @param c the character to display
     */

    public static void println( char c){
        println( Character.toString( c));
    }

    // No need for overridden byte or short methods - will be handled by printLine( int) method below

    /**
     * Print a integer value to the console and
     * terminate with a newline
     *
     * @param i the int value to display
     */

    public static void println( int i){
        println( Integer.toString( i));
    }

    /**
     * Print a long value to the console and
     * terminate with a newline
     *
     * @param l the long value to display
     */

    public static void println( long l){
        println( Long.toString( l));
    }

    // No need for overridden float method - will be handled by printLine( double) method below

    /**
     * Print a floating-point value to the console and
     * terminate with a newline
     *
     * @param d the floating-point value to display
     */

    public static void println( double d){
        println( Double.toString( d));
    }

    /**
     * Print a floating-point value to the console and
     * terminate with a newline
     * The floating-point value is formatted according to
     * the pattern provided
     *
     * @param d the floating-point value to display
     * @param str the pattern to apply
     */

    public static void println( double d, String str){
        DecimalFormat df = new DecimalFormat( str);
        println( df.format( d));
    }

    /**
     * Print a boolean value to the console and
     * terminate with a newline
     *
     * @param b the boolean value to display
     */

    public static void println( boolean b){
        println( Boolean.toString( b));
    }

    // ---------------- End of println() methods ------------

    // ---------------- Start of printRight() methods ------------

    public static void printRight( String s, int width){
        int padding = width - s.length();
        while (--padding >= 0){
            print(" ");
        }
        print( s);
    }

    public static void printRight( Object o, int width){
        printRight( o.toString(), width);
    }

    public static void printRight( char c, int width){
        printRight( Character.toString( c), width);
    }

    public static void printRight( int i, int width){
        printRight( Integer.toString( i), width);
    }

    public static void printRight( long l, int width){
        printRight( Long.toString( l), width);
    }

    public static void printRight( double d, int width){
        printRight( Double.toString( d), width);
    }

    public static void printRight( double d, String str, int width){
        DecimalFormat df = new DecimalFormat( str);
        printRight( df.format( d), width);
    }

    public static void printRight( boolean b, int width){
        printRight( Boolean.toString( b), width);
    }
    // ---------------- End of printRight() methods ------------

    // ---------------- Start of printCenter() methods ------------

    public void printCenter( String s, int width){
        int padLeft = (width - s.length())/2;
        int padRight = padLeft;

        while (--padLeft >= 0){
            print(" ");
        }

        print( s);

        while (--padRight >= 0){
            print(" ");
        }
    }

    // ---------------- End of printCenter() methods ------------

    // ---------------- Start of readXXX() methods ------------

    /**
     * Read a word from the console. The word is
     * any set of characters terminated by whitespace
     *
     * @return the 'word' entered
     */

    public static String readWord(){
        int ch;
        String word = "";
        boolean done = false;
        while (!done){
            try{
                ch = System.in.read();
                if((char) ch == '\r'){
                    ch = System.in.read();  // Skip all this stuff
                }

                if (ch < 0 || Character.isWhitespace((char)ch)){
                    done = true;
                }
                else{
                    word = word + (char) ch;
                }
            }
            catch(IOException ioe){
                done = true;
            }
        }
        return word;
    }

    /**
     * Read a String from the console. The String is
     * terminated by a newline.
     *
     * @return the input string (without the newline)
     */

    public static String readString(){
        int ch;
        String r = "";
        boolean done = false;
        while (!done){
            try{
                ch = System.in.read();
                if (ch < 0 || (char)ch == '\n'){
                    done = true;
                }
                else if ((char)ch != '\r'){
                    r = r + (char)ch;
                }
            }
            catch (IOException ioe){
                done = true;
            }
        }
        return r;
    }

    /**
     * Read a String from the console. The String is
     * terminated by a newline. A console prompt for input
     * in also provided.
     *
     * @param prompt the prompt String to display
     * @return the input String (without the newline)
     */

    public static String readString( String prompt){
        print( prompt);
        return readString();
    }

    /**
     * Read a character from the console. The input is
     * terminated by a newline
     *
     * @return the input value as a character
     * @exception NumberFormatException if bad input
     */

    public static char readChar(){
        while (true){
            try{
                String word = readWord();
                word = word.trim();
                return (char)word.charAt( 0);
            }
            catch(Exception e){
                System.out.println("Not a character. Please try again!");
            }
        }
    }

    /**
     * Read a character from the console. The input is
     * terminated by a newline
     *
     * @param prompt the prompt string to display
     * @return the input value as a character
     */

    public static char readChar( String prompt){
        print( prompt);
        return readChar();
    }

    /*
        Should provide readXXX() methods for other primitive types?
        Missing:
            readByte();
            readShort();
     */

    /**
     * Read an integer from the console. The input is
     * terminated by a newline
     *
     * @return the input value as an int
     * @exception NumberFormatException if bad input
     */

    public static int readInt(){
        while(true){
            try{
                return Integer.valueOf( readWord().trim()).intValue();
             }
             catch(NumberFormatException e){
                 System.out.println("Not an integer. Please try again!");
             }
        }
    }

    /**
     * Read an integer from the console. The input is
     * terminated by a newline
     *
     * @param prompt the prompt string to display
     * @return the input value as an int
     */

    public static int readInt( String prompt){
        print( prompt);
        return readInt();
    }

    public static long readLong(){
        while(true){
            try{
                return Long.valueOf( readWord().trim()).longValue();
             }
             catch(NumberFormatException e){
                 System.out.println( "Not an integer. Please try again!");
             }
        }
    }

    public static long readLong( String prompt){
        print( prompt);
        return readLong();
    }

    /**
     * Read a floating point number from the console.
     * The input is terminated by a newline
     *
     * @return The input value as a double
     * @exception NumberFormatException if bad input
     */

    public static float readFloat(){
        while(true){
             try{
                 return Float.valueOf( readWord().trim()).floatValue();
             }
             catch(NumberFormatException e){
                 System.out.println( "Not a floating point number. Please try again!");
             }
        }
    }

    /**
     * Read a floating point number from the console.
     * The input is terminated by a newline
     *
     * @param prompt The prompt string to display
     * @return The input value as a double
     */

    public static float readFloat( String prompt){
        print( prompt);
        return readFloat();
    }

    /**
     * Read a floating point number from the console.
     * The input is terminated by a newline
     *
     * @return The input value as a double
     * @exception NumberFormatException if bad input
     */

    public static double readDouble(){
        while(true){
             try{
                 return Double.valueOf( readWord().trim()).doubleValue();
             }
             catch(NumberFormatException e){
                 System.out.println( "Not a double value. Please try again!");
             }
        }
    }

    /**
     * Read a floating point number from the console.
     * The input is terminated by a newline
     *
     * @param prompt The prompt string to display
     * @return The input value as a double
     */

    public static double readDouble( String prompt){
        print( prompt);
        return readDouble();
    }

    public static boolean readBoolean(){
        return Boolean.valueOf( readWord().trim()).booleanValue();
    }

    public static boolean readBoolean( String prompt){
        print( prompt);
        return readBoolean();
    }
}